package cn.initcap.concurrency.concurrency.aqs;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;

/**
 * 适用于需要保证线程按照顺序执行的场景，或者指定等待时间的执行场景
 *
 * @author initcap
 * @date Created in 2018/6/17 PM6:05.
 */
@Slf4j
public class CountDownLatchExample {

    private static final int THREAD_SIZE = 200;

    /**
     * 创建线程池
     */
    private static final ExecutorService executorService = new ThreadPoolExecutor(0, THREAD_SIZE,
            60L, TimeUnit.SECONDS, new SynchronousQueue<>(),
            new ThreadFactoryBuilder().setNameFormat("CountDownLatchExample").build());

    public static void main(String[] args) throws Exception {
        final CountDownLatch countDownLatch = new CountDownLatch(THREAD_SIZE);
        // 无限等待 finish一定会在最后面
//        latchExecute(countDownLatch);
        // 只等待指定的时间 finish会在指定的超时时间后出现
        latchTimeout(countDownLatch);
        log.info("finish");
        executorService.shutdown();
    }

    private static void latchTimeout(CountDownLatch countDownLatch) throws InterruptedException {
        // 设置等待时间，超时就放弃处理
        if (!countDownLatch.await(1000, TimeUnit.MILLISECONDS)) {
            execute(countDownLatch);
        }
    }

    private static void latchExecute(CountDownLatch countDownLatch) throws InterruptedException {
        execute(countDownLatch);
        // 用来确保上面的语句都执行完毕才会继续向下执行，这里会无限等待。
        countDownLatch.await();
    }


    private static void execute(CountDownLatch countDownLatch) {
        for (int i = 0; i < THREAD_SIZE; i++) {
            final int threadNum = i;
            executorService.execute(() -> {
                try {
                    test(threadNum);
                } catch (InterruptedException e) {
                    log.error("exception", e);
                    Thread.currentThread().interrupt();
                } finally {
                    countDownLatch.countDown();
                }
            });
        }
    }

    private static void test(int threadNum) throws InterruptedException {
        Thread.sleep(10);
        log.info("{}", threadNum);
        Thread.sleep(10);
    }

}
